package ca.qc.bdeb.jeuxdesboites;

import ca.qc.bdeb.jeuxdesboites.commun.Coup;
import ca.qc.bdeb.utilitaires.Direction;
import ca.qc.bdeb.jeuxdesboites.commun.EvenementPartie;
import ca.qc.bdeb.jeuxdesboites.commun.IDJoueurs;
import ca.qc.bdeb.jeuxdesboites.model.GestionPartie;
import ca.qc.bdeb.jeuxdesboites.model.TableauJeu;
import ca.qc.bdeb.mvc.Observateur;
import ca.qc.bdeb.event.ComponentSelectedEvent;
import ca.qc.bdeb.event.ComponentSelectedListener;
import ca.qc.bdeb.graphiques.Sprite;
import ca.qc.bdeb.graphiques.UtilitairesImages;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/**
 * Cette classe dessine le tableau de jeu et gère les coups fait par le joueur
 * humain.
 *
 * @author Eric Wenaas <eric.wenaas@bdeb.qc.ca>
 * @version 0.3
 */
final class JeuxGUI extends JPanel implements ComponentSelectedListener,
        Observateur
{

    private static final int LARGEUR_POINT = 8;
    private static final int HAUTEUR_POINT = 8;
    private static final int ESPACE_POINT_BARRE = 1;
    private GestionPartie jeu;
    private TableauJeu tableau;
    private Sprite[][] points;
    private LinkedList<BarreSprite> barres;
    private JLabel[][] etiquettesBoites;

    JeuxGUI()
    {
        setLayout(null);
    }

    /**
     * Place le jeu. La partie doit avoir été initialisée afin de placer
     * correctement les éléments du jeu.
     *
     * @param leJeu
     */
    void setJeu(GestionPartie leJeu)
    {
        boolean estHorizontale = true;
        if (jeu != null)
        {
            detruireComposants(); // Les anciens elements d'interface doivent être
            // supprimés.
        }
        jeu = leJeu;
        tableau = leJeu.getTableau();
        points = new Sprite[jeu.LARGEUR_TABLEAU + 1][jeu.HAUTEUR_TABLEAU + 1];
        barres = new LinkedList<>();
        etiquettesBoites = new JLabel[jeu.LARGEUR_TABLEAU][jeu.HAUTEUR_TABLEAU];
        creerPoints();
        creerEtiquettesBoites();
       // creerBarresHorizontales();
        //creerBarresVerticales();
        int boucle1 = jeu.LARGEUR_TABLEAU;
        int boucle2 = jeu.HAUTEUR_TABLEAU + 1;
        creerBarre(1, Direction.HAUT, Direction.BAS, boucle1, boucle2);
        repaint();
    }

    private void detruireComposants()
    {
        for (Sprite tabPoints[] : points)
        {
            for (Sprite point : tabPoints)
            {
                remove(point);
            }
        }
        points = null;

        for (JLabel tabProprietaires[] : etiquettesBoites)
        {
            for (JLabel label : tabProprietaires)
            {
                remove(label);
            }
        }
        etiquettesBoites = null;

        while (!barres.isEmpty())
        {
            remove(barres.removeFirst());
        }
        barres = null;
    }

    private void creerPoints()
    {
        BufferedImage dotImage =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/dot.png"));
        double horizontalGap = (getWidth() - LARGEUR_POINT) / (double) jeu.LARGEUR_TABLEAU;
        double verticalGap = (getHeight() - HAUTEUR_POINT) / (double) jeu.HAUTEUR_TABLEAU;

        for (int i = 0; i < jeu.LARGEUR_TABLEAU + 1; i++)
        {
            for (int j = 0; j < jeu.HAUTEUR_TABLEAU + 1; j++)
            {
                points[i][j] = new Sprite(dotImage);
                points[i][j].setSize(LARGEUR_POINT, HAUTEUR_POINT);
                points[i][j].setLocation((int) (i * horizontalGap),
                        (int) (j * verticalGap));
                points[i][j].setVisible(true);
                add(points[i][j]);
            }
        }
    }

    // TODO: Centrer les étiquettes à l'intérieur de la boîte.
    private void creerEtiquettesBoites()
    {
        for (int x = 0; x < jeu.LARGEUR_TABLEAU; x++)
        {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU; y++)
            {
                int xGauche = points[x][y].getLocation().x + ESPACE_POINT_BARRE + LARGEUR_POINT;
                int xDroit = points[x + 1][y].getLocation().x - LARGEUR_POINT;
                int largeur = xDroit - xGauche;
                int xPosition = xGauche + (largeur - 120) / 2;
                int yHaut = points[x][y].getLocation().y + ESPACE_POINT_BARRE + LARGEUR_POINT;
                int yBas = points[x][y + 1].getLocation().y - ESPACE_POINT_BARRE;
                int hauteur = yBas - yHaut;
                int yPosition = yHaut + (hauteur - 50) / 2;

                JLabel nouvelleEtiquette = new JLabel("", SwingConstants.CENTER);
                nouvelleEtiquette.setSize(120, 50);
                nouvelleEtiquette.setLocation(xPosition, yPosition);
                add(nouvelleEtiquette);
                etiquettesBoites[x][y] = nouvelleEtiquette;
            }
        }
    }

    private void creerBarresHorizontales()
    {
        BufferedImage horizontalImage =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/bar.png"));

        for (int x = 0; x < jeu.LARGEUR_TABLEAU; x++)
        {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU + 1; y++)
            {
                int xPosition = points[x][y].getLocation().x + ESPACE_POINT_BARRE + LARGEUR_POINT;
                int yPosition = points[x][y].getLocation().y;
                int width = points[x + 1][y].getLocation().x - ESPACE_POINT_BARRE - xPosition;
                Coup pos;
                if (y == 0)
                {
                    pos = new Coup(x, y, Direction.HAUT);
                }
                else
                {
                    pos = new Coup(x, y - 1, Direction.BAS);
                }
                BarreSprite nouveauSprite = new BarreSprite(horizontalImage, pos);
                nouveauSprite.setSize(width, HAUTEUR_POINT);
                nouveauSprite.setLocation(xPosition, yPosition);
                nouveauSprite.addComponentSelectedListener(this);
                add(nouveauSprite);
                barres.add(nouveauSprite);
            }
        }
    }

    private void creerBarre(int estHorizontale, Direction direction1,
            Direction direction2, int boucle1, int boucle2)
    {
        BufferedImage image =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/bar.png"));
        
        int xPosition = 0, yPosition = 0;
        int grandeur = 0; 
        
        if (estHorizontale == 2)
        {
            direction1 = Direction.GAUCHE;
            direction2 = Direction.DROIT;
            boucle1 = jeu.LARGEUR_TABLEAU + 1;
            boucle2 = jeu.HAUTEUR_TABLEAU;
           // estHorizontale = 3;
        }
        else
        {
        }
        if (estHorizontale != 3)
        {
            Coup pos;
            for (int x = 0; x < boucle1; x++)
            {
                for (int y = 0; y < boucle2; y++)
                {
                    
                    if (estHorizontale == 1)
                    {
                        xPosition = points[x][y].getLocation().x + ESPACE_POINT_BARRE + LARGEUR_POINT;
                        yPosition = points[x][y].getLocation().y;
                        grandeur = points[x + 1][y].getLocation().x - ESPACE_POINT_BARRE - xPosition;
                        if (y == 0)
                        {
                            pos = new Coup(x, y, direction1);
                        }
                        else
                        {
                            pos = new Coup(x, y - 1, direction2);
                        }
                    }
                    else if (estHorizontale == 2)
                    {
                        xPosition = points[x][y].getLocation().x;
                        yPosition = points[x][y].getLocation().y + ESPACE_POINT_BARRE + HAUTEUR_POINT;
                        grandeur = points[x][y + 1].getLocation().y - ESPACE_POINT_BARRE - yPosition;
                        if (x == 0) 
                        {
                            pos = new Coup(x, y, direction1);
                        } 
                        else 
                        {
                            pos = new Coup(x - 1, y, direction2);
                        }
                    }
                    BarreSprite nouveauSprite = new BarreSprite(image, pos);
                    if (estHorizontale == 1)
                    {
                        nouveauSprite.setSize(grandeur, HAUTEUR_POINT);
                    }
                    else if (estHorizontale == 2)
                    {
                        nouveauSprite.setSize(LARGEUR_POINT, grandeur);
                    }
                    
                    nouveauSprite.setLocation(xPosition, yPosition);
                    nouveauSprite.addComponentSelectedListener(this);
                    add(nouveauSprite);
                    barres.add(nouveauSprite);
                }
            }
            boucle1 = jeu.LARGEUR_TABLEAU + 1;
            boucle2 = jeu.HAUTEUR_TABLEAU;
            creerBarre(estHorizontale, Direction.GAUCHE, Direction.DROIT, boucle1, boucle2);
            ++estHorizontale;
        }
    }

    private void creerBarresVerticales()
    {
        BufferedImage verticalImage =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/bar.png"));
        UtilitairesImages.faireRotation(verticalImage, 90);
        for (int x = 0; x < jeu.LARGEUR_TABLEAU + 1; x++)
        {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU; y++)
            {
                int xPosition = points[x][y].getLocation().x;
                int yPosition = points[x][y].getLocation().y + ESPACE_POINT_BARRE + HAUTEUR_POINT;
                int height = points[x][y + 1].getLocation().y - ESPACE_POINT_BARRE - yPosition;
                Coup pos;
                if (x == 0)
                {
                    pos = new Coup(x, y, Direction.GAUCHE);
                }
                else
                {
                    pos = new Coup(x - 1, y, Direction.DROIT);
                }
                BarreSprite nouveauSprite = new BarreSprite(verticalImage, pos);
                nouveauSprite.setSize(LARGEUR_POINT, height);
                nouveauSprite.setLocation(xPosition, yPosition);
                nouveauSprite.addComponentSelectedListener(this);
                add(nouveauSprite);
                barres.add(nouveauSprite);
            }
        }
    }

    private void mettreAJour()
    {
        mettreAJourBarres();
        mettreAJourNoms();
    }

    private void mettreAJourBarres()
    {
        IDJoueurs joueurActuel = jeu.getJoueurActuel();
        boolean humainAJouer = joueurActuel.equals(IDJoueurs.JOUEUR_HUMAIN);
        for (BarreSprite sprite : barres)
        {
            Coup c = sprite.getPosition();
            int x = c.positionX;
            int y = c.positionY;
            Direction d = c.direction;
            if (tableau.isFermee(x, y, d))
            {
                sprite.fermerBarre();
            }
            else
            {
                sprite.ouvrirBarre();
            }
            if (humainAJouer)
            {
                sprite.activerBarre();
            }
            else
            {
                sprite.desactiverBarre();
            }
        }
    }

    private void mettreAJourNoms()
    {
        String nomAI = jeu.getNomJoueur(IDJoueurs.JOUEUR_ARTIFICIEL);
        String nomHumain = jeu.getNomJoueur(IDJoueurs.JOUEUR_HUMAIN);
        for (int x = 0; x < jeu.LARGEUR_TABLEAU; x++)
        {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU; y++)
            {
                IDJoueurs joueur = tableau.getProprietaire(x, y);
                if (joueur != null)
                {
                    String nom = joueur.equals(IDJoueurs.JOUEUR_ARTIFICIEL) ? nomAI : nomHumain;
                    etiquettesBoites[x][y].setText(nom);
                }
            }
        }
    }

    void activerDesactiverCoups()
    {
        boolean humainAJouer = jeu.getJoueurActuel().equals(IDJoueurs.JOUEUR_HUMAIN);
        for (BarreSprite sprite : barres)
        {
            if (humainAJouer)
            {
                sprite.activerBarre();
            }
            else
            {
                sprite.desactiverBarre();
            }
        }
    }

    // Méthodes de l'interface ComponentSelectedListener
    @Override
    public void onComponentSelectedEvent(ComponentSelectedEvent evt)
    {
        BarreSprite sprite = (BarreSprite) (evt.getSource());
        Coup leCoup = sprite.getPosition();
        jeu.jouerCoup(IDJoueurs.JOUEUR_HUMAIN, leCoup);
    }

    // Méthodes de l'interface Observateur
    @Override
    public void changementEtat()
    {
        mettreAJour();
    }

    @Override
    public void changementEtat(Enum<?> property, Object o)
    {
        if (property.equals(EvenementPartie.COUPS_REQUIS))
        {
            activerDesactiverCoups();
        }
    }
}
